/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.primitives.unix;

import java.io.File;

import fr.x9c.cadmium.kernel.CodeRunner;
import fr.x9c.cadmium.kernel.Fail;
import fr.x9c.cadmium.kernel.Misc;
import fr.x9c.cadmium.kernel.Primitive;
import fr.x9c.cadmium.kernel.PrimitiveProvider;
import fr.x9c.cadmium.kernel.Value;

/**
 * This class provides implementation for 'unix_access' primitive.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.0
 * @since 1.0
 */
@PrimitiveProvider
public final class Access {

    /** Test for read permission. */
    private static final int READ_OK = 4;

    /** Test for write permission. */
    private static final int WRITE_OK = 2;

    /** Test for execute permission. */
    private static final int EXEC_OK = 1;

    /** Test for file presence. */
    private static final int FILE_OK = 0;

    /** Conversion table for permission flags. */
    private static final int[] TABLE = {
        Access.READ_OK,
        Access.WRITE_OK,
        Access.EXEC_OK,
        Access.FILE_OK
    };

    /**
     * No instance of this class.
     */
    private Access() {
    } // end empty constructor

    /**
     * Checks a file for access permissions, raising an exception if check fails.
     * @param ctxt context
     * @param path file to check
     * @param perms list of permissions to check
     * @return <i>unit</i>
     * @throws Fail.Exception if requested permissions are not granted
     */
    @Primitive
    public static Value unix_access(final CodeRunner ctxt,
                                    final Value path,
                                    final Value perms)
        throws Fail.Exception {
        final int flags = Misc.convertFlagList(perms, Access.TABLE);
        final File f = ctxt.getContext().getRealFile(path);
        boolean error = false;
        if ((flags & Access.FILE_OK) != 0) {
            error |= !f.exists();
        } // end if
        if ((flags & Access.READ_OK) != 0) {
            error |= !f.canRead();
        } // end if
        if ((flags & Access.WRITE_OK) != 0) {
            error |= !f.canWrite();
        } // end if
        if ((flags & Access.EXEC_OK) != 0) {
            error |= !f.canExecute();
        } // end if
        if (error) {
            Unix.fail(ctxt, "access", "requested file permissions not granted");
        } // end if
        return Value.UNIT;
    } // end method 'unix_access(CodeRunner, Value, Value)'

} // end class 'Access'
